package org.iabako.server.serviceimpl.function;

import org.apache.jempbox.xmp.XMPMetadata;
import org.apache.jempbox.xmp.XMPSchemaDublinCore;
import org.apache.log4j.Logger;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDPixelMap;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
import org.apache.poi.util.IOUtils;
import org.iabako.server.dao.business.PaymentDAO;
import org.iabako.server.dao.business.SaleDAO;
import org.iabako.server.dao.user.EnterpriseDAO;
import org.iabako.server.mail.IabakoMailHelper;
import org.iabako.server.mail.IabakoMailSender;
import org.iabako.server.serviceimpl.security.SessionUser;
import org.iabako.server.tools.*;
import org.iabako.server.tools.pdftable.PdfCell;
import org.iabako.server.tools.pdftable.PdfRow;
import org.iabako.server.tools.pdftable.PdfTable;
import org.iabako.server.tools.pdftable.PdfWriterHelper;
import org.iabako.shared.entity.business.*;
import org.iabako.shared.entity.enumeration.FinancialStatusSale;
import org.iabako.shared.entity.enumeration.Language;
import org.iabako.shared.entity.enumeration.PaymentMethod;
import org.iabako.shared.entity.enumeration.TrackingType;
import org.iabako.shared.entity.user.Enterprise;
import org.iabako.shared.entity.user.EnterpriseCustomInfo;
import org.iabako.shared.exception.IabakoActionForbiddenException;
import org.iabako.shared.exception.IabakoUniqueConstraintException;
import org.iabako.shared.iservice.business.QuoteService;
import org.iabako.shared.iservice.business.TrackingService;
import org.iabako.shared.iservice.function.InvoiceGeneratorService;
import org.iabako.shared.tools.GenericTools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Created by jose on 05/02/15.
 */

@org.springframework.stereotype.Service("invoiceGeneratorService")
public class InvoiceGeneratorServiceImpl implements InvoiceGeneratorService {

    static Logger log = Logger.getLogger(InvoiceGeneratorServiceImpl.class.getName());

    final private String INVOICE_STATUS_IMAGE_PREFIX = "/org/iabako/public/invoice_status/invoice_status";

    @Autowired
    EnterpriseDAO enterpriseDAO;
    @Autowired
    SaleDAO saleDAO;
    @Autowired
    QuoteService quoteService;
    @Autowired
    PaymentDAO paymentDAO;
    @Autowired
    BundleMessages messages;
    @Autowired
    PdfInvoiceTableHelper pdfInvoiceTableHelper;
    @Autowired
    IabakoMailSender iabakoMailSender;
    @Autowired
    SessionUser sessionUser;
    @Autowired
    TrackingService trackingService;

    public void sendInvoiceByEmail(Sale sale, Long idPayment, String invoiceNumber, String email, String subject, String body) throws IOException {
        String fileTokenInSession = generateInvoice(sale, idPayment, invoiceNumber, false);
        sendInvoiceByEmail(sale, fileTokenInSession, email, subject, body);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void sendQuoteByEmail(Sale saleFromGWT, List<SaleProductService> productServiceList, String email, String subject, String body) throws IOException, IabakoUniqueConstraintException, IabakoActionForbiddenException {
        Sale sale = quoteService.save(saleFromGWT, productServiceList);
        String fileTokenInSession = generateInvoice(sale, null, sale.getNumber());
        sendInvoiceByEmail(sale, fileTokenInSession, email, subject, body);
    }

    private void sendInvoiceByEmail(Sale sale, String fileTokenInSession, String email, String subject, String body) throws IOException {
        HttpSession session = (((ServletRequestAttributes) RequestContextHolder.
                currentRequestAttributes()).getRequest()).getSession();

        String fileAbsolutePath = (String) session.getAttribute(fileTokenInSession);
        String fileName = (String) session.getAttribute(fileTokenInSession + "_fileTitle");

        FileInputStream in = new FileInputStream(fileAbsolutePath);

        Enterprise enterprise = sessionUser.getUser().getEnterprise();
        enterprise = enterprise.getParentEnterprise() != null ? enterprise.getParentEnterprise() : enterprise;

        IabakoMailHelper iabakoMailHelper = new IabakoMailHelper(null, enterprise.getName(), email, subject, body);

        iabakoMailHelper.setNoReplyEmail(true);
        iabakoMailHelper.setDisableIabakoLogo(true);
        iabakoMailHelper.setAddEnterpriseLogo(true);
        iabakoMailHelper.setDisableDefaultFooter(true);
        iabakoMailHelper.setEnablePoweredByFooter(true);

        iabakoMailHelper.getAttachments().put(fileName, new ByteArrayResource(IOUtils.toByteArray(in)));
        in.close();

        iabakoMailSender.sendMail(iabakoMailHelper);

        session.removeAttribute(fileTokenInSession);
        session.removeAttribute(fileTokenInSession + "_fileTitle");

        File tmpFile = new File(fileAbsolutePath);
        tmpFile.delete();

        if (sale.isQuote()) {
            trackingService.addTrackingToUserSession(TrackingType.quoteSentByEmail, sale);
        } else {
            trackingService.addTrackingToUserSession(TrackingType.invoiceSentByEmail, sale);
        }
    }

    public String generateSampleInvoice(Enterprise transientEnterprise, List<EnterpriseCustomInfo> transientCustomInfoList) {
        //Add logo to Enterprise transient object
        Enterprise enterpriseFromDB = enterpriseDAO.findById(transientEnterprise.getId());
        transientEnterprise.setLogo(enterpriseFromDB.getLogo());
        transientEnterprise.setCustomInfoList(transientCustomInfoList);

        return generateInvoice(transientEnterprise, getSampleSale(), null, null, false);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String generateInvoiceForQuote(Sale saleFromGWT, List<SaleProductService> productServiceList) throws IabakoUniqueConstraintException, IabakoActionForbiddenException {
        Sale sale = quoteService.save(saleFromGWT, productServiceList);
        return generateInvoice(sale, null, sale.getNumber());
    }

    public String generateInvoice(Sale sale, Long idPayment, String invoiceNumber) {
        return generateInvoice(sale, idPayment, invoiceNumber, true);
    }

    private String generateInvoice(Sale sale, Long idPayment, String invoiceNumber, boolean track) {
        Enterprise enterprise = sessionUser.getUser().getEnterprise();
        enterprise.setCustomInfoList(enterpriseDAO.getCustomInfoList());
        return generateInvoice(enterprise, sale, idPayment, invoiceNumber, track);
    }

    private String generateInvoice(Enterprise enterprise, Sale sale, Long idPayment, String invoiceNumber, boolean track) {
        if (sale == null) {
            return null;
        }

        enterprise = enterprise.getParentEnterprise() != null ? enterprise.getParentEnterprise() : enterprise;

        List<Payment> paymentList = sale.getPayments().isEmpty() ? saleDAO.getPayments(sale) : sale.getPayments();
        List<Installment> installmentList = sale.getInstallments().isEmpty() ? saleDAO.getInstallments(sale) : sale.getInstallments();
        //This is important if changes have been done and generation is executed before save action
        sale.setPayments(paymentList);
        sale.setInstallments(installmentList);
        if (sale.isQuote() && sale.getStatus() == FinancialStatusSale._0_quote_draft) {
            sale.setStatus(FinancialStatusSale._1_quote_generated);
        } else if (!sale.isQuote()) {
            sale.calculateStatus(false);
        }

        Payment selectedPayment = null;

        if (idPayment != null) {
            for (Payment p : paymentList) {
                if (p.getId().equals(idPayment)) {
                    selectedPayment = p;
                }
            }
        }

        invoiceNumber = invoiceNumber == null ? sale.getNumber() : invoiceNumber;
        PDDocument doc = new PDDocument();
        String fileNamePrefix = messages.getLabel(sale.isQuote() ? "" : selectedPayment != null ? "receipt_file_name" : "invoice_file_name") + invoiceNumber;
        try {
            addMetaData(doc, fileNamePrefix);
            PdfWriterHelper pdfWriterHelper = new PdfWriterHelper(20, doc,
                    messages.getLabel("invoice_generation_date"),
                    messages.getLabel("invoice_pagination"));

            addInvoiceStatus(doc, pdfWriterHelper, enterprise.getLanguage(), sale, selectedPayment);

            if (enterprise.getLogo() != null) {
                pdfWriterHelper.moveTopPointer(-10);
                addEnterpriseLogo(doc, pdfWriterHelper, enterprise.getLogo());
            } else {
                pdfWriterHelper.top -= 25;
            }

            String enterpriseInfo = getInfo(enterprise.getCustomInfoList(), enterprise.getWebSite(), enterprise.getEmail(),
                    enterprise.getAddress(), enterprise.getPhoneNumber());

            String clientName = null;
            String clientInfo = null;
            boolean hasInvoiceRecipient = sale.getInvoiceRecipient() != null;

            if (hasInvoiceRecipient || sale.getClient() != null) {
                clientName = hasInvoiceRecipient ? sale.getInvoiceRecipient().getName() : sale.getClient().getName();
                String clientEmail = hasInvoiceRecipient ? sale.getInvoiceRecipient().getEmail() : sale.getClient().getEmail();
                Address address = hasInvoiceRecipient ? sale.getInvoiceRecipient().getAddress() : sale.getClient().getAddress();
                String phoneNumber = hasInvoiceRecipient ? sale.getInvoiceRecipient().getPhoneNumber() : sale.getClient().getPhoneNumber1();

                clientInfo = getInfo(null, null, clientEmail, address, phoneNumber);
            }

            addBlocksSenderAndRecipient(pdfWriterHelper, enterprise.getName(), enterpriseInfo, clientName, clientInfo);

            boolean oneShotSale = paymentList.size() == 1 && installmentList.size() == 0;

            String paymentMethod = oneShotSale && sale.getPaymentMethod() != null ? messages.getLabel(sale.getPaymentMethod().getLabelKey()) : null;
            String paymentDate = oneShotSale ? GenericTools.formatDate(paymentList.get(0).getDate()) : null;

            pdfWriterHelper.moveTopPointer(10);
            PdfTable dateBlock = addDateAndMethodInfo(pdfWriterHelper, GenericTools.formatDate(sale.getDate()), paymentDate, paymentMethod, sale.isQuote());

            pdfWriterHelper.margin = pdfWriterHelper.initMargin;
            PdfTable invoiceNumberBlock = addInvoiceNumber(pdfWriterHelper, invoiceNumber, sale.isQuote(), selectedPayment != null, dateBlock.getNextYpos() + 30);

            if (dateBlock.getNextYpos() < invoiceNumberBlock.getNextYpos() + 30) {
                pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - dateBlock.getNextYpos() + 10);
            } else {
                pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - invoiceNumberBlock.getNextYpos() + 40);
            }

            pdfWriterHelper.margin = pdfWriterHelper.initMargin;

            List<SaleProductService> productServiceList = sale.getProductsServices().isEmpty() ? saleDAO.getProductServiceList(sale) : sale.getProductsServices();
            sale.setProductsServices(productServiceList);

            generateProductServiceTable(pdfWriterHelper, sale, paymentList, installmentList);
            pdfWriterHelper.moveTopPointer(10);

            if (!oneShotSale && selectedPayment == null && (!paymentList.isEmpty() || !installmentList.isEmpty())) {
                pdfWriterHelper.margin = pdfWriterHelper.initMargin;
                if (!paymentList.isEmpty()) {
                    generatePaymentInstallmentTable(pdfWriterHelper, "invoice_payment_title", sale, paymentList, null);
                    pdfWriterHelper.moveTopPointer(10);
                }
                if (!installmentList.isEmpty()) {
                    generatePaymentInstallmentTable(pdfWriterHelper, "invoice_installment_title", sale, null, installmentList);
                }

            } else if (selectedPayment != null) {
                generatePaymentInstallmentTable(pdfWriterHelper, "invoice_one_payment_title", sale, Arrays.asList(selectedPayment), null);
            }

            pdfWriterHelper.moveTopPointer(20);
            pdfWriterHelper.margin = pdfWriterHelper.initMargin;
            String comment = "";
            if (oneShotSale) {
                comment = !GenericTools.isEmpty(sale.getComment()) ?
                        "- " + sale.getComment() + "\n\n- " + paymentList.get(0).getComment() :
                        paymentList.get(0).getComment();
            } else if (selectedPayment != null) {
                comment = selectedPayment.getComment();
            } else {
                comment = sale.getComment();
            }
            addCommentInfo(pdfWriterHelper, comment);

            addCustomNote(pdfWriterHelper, enterprise.getInvoiceNote());

            // Write the output to a tmp file
            File tmpFile = File.createTempFile("iabako_pdf_file", ".pdf");
            //Close Stream and save pdf
            pdfWriterHelper.endFile();
            doc.save(tmpFile);
            doc.close();

            FileTools.addFileToSession(tmpFile, fileNamePrefix + ".pdf");

            if (track) {
                if (sale.isQuote()) {
                    trackingService.addTrackingToUserSession(TrackingType.quoteDownloaded, sale);
                } else {
                    trackingService.addTrackingToUserSession(TrackingType.invoiceDownloaded, sale);
                }
            }

            return tmpFile.getName();

        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } catch (COSVisitorException e) {
            log.error(e.getMessage(), e);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    private void addMetaData(PDDocument doc, String fileName) throws Exception {

        PDDocumentCatalog catalog = doc.getDocumentCatalog();
        XMPMetadata metadata = new XMPMetadata();
        XMPSchemaDublinCore dcSchema = metadata.addDublinCoreSchema();
        dcSchema.setTitle(fileName);
        dcSchema.addCreator("IABAKO");
        dcSchema.setAbout("");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        dcSchema.addDate(calendar);

        PDMetadata metadataStream = new PDMetadata(doc);
        metadataStream.importXMPMetadata(metadata.asByteArray());

        catalog.setMetadata(metadataStream);
    }

    private void addBlocksSenderAndRecipient(PdfWriterHelper pdfWriterHelper, String enterpriseName, String enterpriseInfo,
                                             String clientName, String clientInfo) throws IOException {
        float tableWidth = PdfWriterHelper.CONTACT_TABLE_WIDTH;

        //Dynamic heights cells
        PdfCell enterpriseDynamicCell = new PdfCell(tableWidth, enterpriseInfo);
        enterpriseDynamicCell.setFont(PDType1Font.HELVETICA);
        enterpriseDynamicCell.setFillColor(PdfWriterHelper.lightGray);
        enterpriseDynamicCell.setTextColor(java.awt.Color.DARK_GRAY);
        float clientDynamicCellHeight = PdfWriterHelper.getHeightOfCell(enterpriseDynamicCell, 20, 10, 8);

        PdfCell clientDynamicCell = new PdfCell(tableWidth, clientInfo);
        clientDynamicCell.setFont(PDType1Font.HELVETICA);
        clientDynamicCell.setFillColor(PdfWriterHelper.lightGray);
        clientDynamicCell.setTextColor(java.awt.Color.DARK_GRAY);
        float enterpriseDynamicCellHeight = PdfWriterHelper.getHeightOfCell(clientDynamicCell, 20, 10, 8);

        PdfTable enterpriseBlock = addInfoBlock(pdfWriterHelper, messages.getLabel("invoice_sender"), enterpriseName);
        PdfRow headerRow = new PdfRow(Math.max(enterpriseDynamicCellHeight, clientDynamicCellHeight));
        headerRow.addCell(enterpriseDynamicCell);
        enterpriseBlock.drawRow(headerRow);
        enterpriseBlock.endTable();
        pdfWriterHelper.moveTopPointer(-15);
        PdfTable clientBlock = null;
        if (clientName != null && clientInfo != null) {
            pdfWriterHelper.margin = pdfWriterHelper.getPageWidth() - PdfWriterHelper.CONTACT_TABLE_WIDTH - pdfWriterHelper.initMargin;
            clientBlock = addInfoBlock(pdfWriterHelper, messages.getLabel("invoice_recipient"), clientName);

            headerRow = new PdfRow(Math.max(enterpriseDynamicCellHeight, clientDynamicCellHeight));
            headerRow.addCell(clientDynamicCell);
            clientBlock.drawRow(headerRow);
            clientBlock.endTable();
            pdfWriterHelper.moveTopPointer(-15);
        }

        pdfWriterHelper.margin = pdfWriterHelper.initMargin;
        if (clientBlock != null && clientBlock.getNextYpos() < enterpriseBlock.getNextYpos()) {
            pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - clientBlock.getNextYpos());
        } else {
            pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - enterpriseBlock.getNextYpos());
        }
    }

    private void addEnterpriseLogo(PDDocument doc, PdfWriterHelper pdfWriterHelper, byte[] logo) throws IOException {
        InputStream inputStream = new ByteArrayInputStream(logo);
        BufferedImage image = ImageIO.read(inputStream);

        PDXObjectImage xImage = new PDPixelMap(doc, image);
        float scale = getScale(xImage.getWidth(), xImage.getHeight());
        float widthResize = xImage.getWidth() * scale;
        float heightResize = xImage.getHeight() * scale;

        float xPos = widthResize < 300 ? pdfWriterHelper.page.findMediaBox().getWidth() / 2 - (widthResize / 2)
                : pdfWriterHelper.initMargin;
        float yPos = pdfWriterHelper.top - heightResize;
        pdfWriterHelper.pageContentStream.drawXObject(xImage, xPos, yPos, widthResize, heightResize);

        pdfWriterHelper.top -= heightResize + 10 > 25 ? heightResize + 10 : 25;
    }

    private float getScale(int width, int height) {
        float maxHeight = 100;
        float maxWidth = 500;

        float scaleWidth = maxWidth / width;
        float scaleHeight = maxHeight / height;

        return scaleWidth > 0.7 && scaleHeight > 0.7 ? 0.7f
                : scaleWidth < 0.7 && scaleHeight < 0.7 ? scaleWidth < scaleHeight ? scaleWidth : scaleHeight
                : scaleWidth < 0.7 ? scaleWidth
                : scaleHeight;
    }

    private void addInvoiceStatus(PDDocument doc, PdfWriterHelper pdfWriterHelper, Language language, Sale sale, Payment selectedPayment) throws IOException {

        String invoiceStatusImage = INVOICE_STATUS_IMAGE_PREFIX;
        if (selectedPayment != null) {
            invoiceStatusImage += "_payed_" + language.getLangString();
        } else {
            switch (sale.getStatus()) {
                case _3_OK:
                    invoiceStatusImage += "_payed_" + language.getLangString();
                    break;
                case _1_inDebt:
                    invoiceStatusImage += "_pending_" + language.getLangString();
                    break;
                case _2_withFutureInstallments:
                    invoiceStatusImage += "_future_" + language.getLangString();
                    break;
                default:
                    invoiceStatusImage += "_quote_" + language.getLangString();
                    break;
            }
        }

        URL logoImage = this.getClass().getClassLoader().getResource(invoiceStatusImage + ".png");
        BufferedImage image = ImageIO.read(new FileInputStream(logoImage.getFile()));

        PDXObjectImage xImage = new PDPixelMap(doc, image);
        float widthResize = new Float(xImage.getWidth() * 0.4);
        float heightResize = new Float(xImage.getHeight() * 0.4);

        float xPos = pdfWriterHelper.page.findMediaBox().getWidth() - widthResize - pdfWriterHelper.initMargin;
        float yPos = pdfWriterHelper.page.findMediaBox().getHeight() - 10 - heightResize;
        pdfWriterHelper.pageContentStream.drawXObject(xImage, xPos, yPos, widthResize, heightResize);
    }

    private void generatePaymentInstallmentTable(PdfWriterHelper pdfWriterHelper, String titleKey, Sale sale,
                                                 List<Payment> paymentList, List<Installment> installmentList) throws IOException {

        PdfInvoiceTableDescriptor tableDescriptor =
                new PdfInvoiceTableDescriptor(messages.getLabel(titleKey), sale.isProductServiceWithDifferentTaxes(), sale.isProductServiceWithTax());

        tableDescriptor.setPayments(paymentList);
        tableDescriptor.setInstallments(installmentList);

        PdfTable productServiceTable = pdfInvoiceTableHelper.addPaymentTable(pdfWriterHelper, tableDescriptor);
        pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - (productServiceTable.getNextYpos() - 5));
        pdfInvoiceTableHelper.addTotal(pdfWriterHelper, sale, paymentList, installmentList, false);
    }

    private void generateProductServiceTable(PdfWriterHelper pdfWriterHelper, Sale sale,
                                             List<Payment> paymentList, List<Installment> installmentList) throws IOException {
        PdfInvoiceTableDescriptor tableDescriptor = new PdfInvoiceTableDescriptor(
                messages.getLabel("invoice_product_service_title"), sale.isProductServiceWithDifferentTaxes(), sale.isProductServiceWithTax());

        tableDescriptor.setProductServices(sale.getProductsServices());

        PdfTable productServiceTable = pdfInvoiceTableHelper.addProductServiceTable(pdfWriterHelper, tableDescriptor);
        pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - (productServiceTable.getNextYpos() - 5));
        pdfInvoiceTableHelper.addTotal(pdfWriterHelper, sale, paymentList, installmentList, true);
    }

    private String getInfo(List<EnterpriseCustomInfo> customInfoList, String website, String email, Address address, String phoneNumber) {
        String info = address.getAddressLine1();
        info += !GenericTools.isEmpty(address.getAddressLine2()) ? "\n" + address.getAddressLine2() : "";
        info += "\n" + (!GenericTools.isEmpty(address.getZipCode()) ? address.getZipCode() + " " : "");
        info += address.getCity() + " - " + messages.getLabel(address.getCountry().getLabelKey());
        info += "\n" + phoneNumber;
        info += !GenericTools.isEmpty(email) ? "\n" + email + "\n" : "";
        info += !GenericTools.isEmpty(website) ? website + "\n" : "";

        if (customInfoList != null) {
            info += "\n";
            for (EnterpriseCustomInfo customInfo : customInfoList) {
                info += customInfo.getTitle() + " : " + customInfo.getValue() + "\n";
            }
        }

        return info;
    }

    private static PdfTable addInfoBlock(PdfWriterHelper pdfWriterHelper, String titleString, String name) throws IOException {

        PdfTable titleTable = new PdfTable(pdfWriterHelper);
        titleTable.setLineColor(Color.WHITE);
        PdfRow headerRow = new PdfRow(15f);
        PdfCell cell = new PdfCell(PdfWriterHelper.CONTACT_TABLE_WIDTH, titleString);
        cell.setFont(PDType1Font.HELVETICA);
        cell.setFillColor(Color.GRAY);
        cell.setTextColor(Color.WHITE);
        headerRow.addCell(cell);
        titleTable.drawRow(headerRow);
        titleTable.endTable();

        pdfWriterHelper.moveTopPointer(15);

        PdfTable enterpriseInfoTable = new PdfTable(pdfWriterHelper);
        enterpriseInfoTable.setHorizontalCellMargin(20);
        enterpriseInfoTable.setLineColor(PdfWriterHelper.lightGray);
        enterpriseInfoTable.setLineWidth(0);

        headerRow = new PdfRow(20f);
        cell = new PdfCell(PdfWriterHelper.CONTACT_TABLE_WIDTH, "\n" + name);
        cell.setFontSize(10);
        cell.setFont(PDType1Font.HELVETICA_BOLD);
        cell.setFillColor(PdfWriterHelper.lightGray);
        cell.setTextColor(java.awt.Color.DARK_GRAY);
        headerRow.addCell(cell);
        enterpriseInfoTable.drawRow(headerRow);

        return enterpriseInfoTable;
    }

    private PdfTable addDateAndMethodInfo(PdfWriterHelper pdfWriterHelper, String saleDateInfo,
                                          String paymentDateInfo, String paymentMethod, boolean isQuote) throws IOException {

        pdfWriterHelper.margin = pdfWriterHelper.getPageWidth() - pdfWriterHelper.initMargin - 192;
        boolean isWithPaymentInfo = paymentDateInfo != null && paymentMethod != null;

        PdfTable paymentInfo = new PdfTable(pdfWriterHelper);
        paymentInfo.setHorizontalCellMargin(15);
        paymentInfo.setVerticalCellMargin(5);
        if (isWithPaymentInfo) {
            paymentInfo.setLineColor(java.awt.Color.DARK_GRAY);
            paymentInfo.setLineWidth(1.5f);
        } else {
            paymentInfo.setLineWidth(0);
            paymentInfo.setLineColor(Color.WHITE);
        }
        PdfRow headerRow = new PdfRow(15f);
        PdfCell cell = new PdfCell(115, isQuote ? messages.getLabel("invoice_quote_date") : messages.getLabel("invoice_sale_date"));
        cell.setNoLine(true);
        cell.setFont(PDType1Font.HELVETICA_BOLD);
        cell.setFillColor(java.awt.Color.WHITE);
        cell.setTextColor(java.awt.Color.DARK_GRAY);
        headerRow.addCell(cell);
        cell = new PdfCell(75, saleDateInfo);
        cell.setNoLine(true);
        cell.setFont(PDType1Font.HELVETICA);
        cell.setFillColor(java.awt.Color.WHITE);
        cell.setTextColor(java.awt.Color.DARK_GRAY);
        headerRow.addCell(cell);
        paymentInfo.drawRow(headerRow);
        if (isWithPaymentInfo) {
            headerRow = new PdfRow(15f);
            headerRow.setNoLine(true);
            cell = new PdfCell(115, messages.getLabel("invoice_payment_date"));
            cell.setNoLine(true);
            cell.setFont(PDType1Font.HELVETICA_BOLD);
            cell.setFillColor(java.awt.Color.WHITE);
            cell.setTextColor(java.awt.Color.DARK_GRAY);
            headerRow.addCell(cell);
            cell = new PdfCell(75, paymentDateInfo);
            cell.setNoLine(true);
            cell.setFont(PDType1Font.HELVETICA);
            cell.setFillColor(java.awt.Color.WHITE);
            cell.setTextColor(java.awt.Color.DARK_GRAY);
            headerRow.addCell(cell);
            paymentInfo.drawRow(headerRow);

            headerRow = new PdfRow(15f);
            headerRow.setNoLine(true);
            cell = new PdfCell(115, messages.getLabel("invoice_payment_method"));
            cell.setNoLine(true);
            cell.setFont(PDType1Font.HELVETICA_BOLD);
            cell.setFillColor(java.awt.Color.WHITE);
            cell.setTextColor(java.awt.Color.DARK_GRAY);
            headerRow.addCell(cell);
            cell = new PdfCell(75, paymentMethod);
            cell.setNoLine(true);
            cell.setFont(PDType1Font.HELVETICA);
            cell.setFillColor(java.awt.Color.WHITE);
            cell.setTextColor(java.awt.Color.DARK_GRAY);
            headerRow.addCell(cell);
            paymentInfo.drawRow(headerRow);
        }

        paymentInfo.endTable();
        return paymentInfo;
    }

    private PdfTable addInvoiceNumber(PdfWriterHelper pdfWriterHelper, String invoiceNumber, boolean isQuote, boolean isReceipt, float minTopPosition) throws IOException {

        if (pdfWriterHelper.top > minTopPosition) {
            pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - (minTopPosition));
        }

        PdfTable invoiceInfo = new PdfTable(pdfWriterHelper);
        invoiceInfo.setLineColor(Color.WHITE);
        invoiceInfo.setLineWidth(0);
        float tableWidth = 285;
        PdfRow headerRow = new PdfRow(25f);
        PdfCell cell = new PdfCell(tableWidth / 3, isQuote ? messages.getLabel("quote_number") : isReceipt ? messages.getLabel("receipt_number") : messages.getLabel("invoice_number"));
        cell.setFontSize(12);
        cell.setFont(PDType1Font.HELVETICA_BOLD);
        cell.setFillColor(Color.WHITE);
        cell.setTextColor(Color.DARK_GRAY);
        headerRow.addCell(cell);
        cell = new PdfCell(tableWidth * 2 / 3, invoiceNumber);
        cell.setFontSize(12);
        cell.setFont(PDType1Font.HELVETICA);
        cell.setFillColor(Color.WHITE);
        cell.setTextColor(Color.DARK_GRAY);
        headerRow.addCell(cell);
        invoiceInfo.drawRow(headerRow);

        invoiceInfo.endTable();
        return invoiceInfo;
    }

    private void addCommentInfo(PdfWriterHelper pdfWriterHelper, String comment) throws IOException {

        PdfCell commentCell = new PdfCell(390, GenericTools.isEmpty(comment) ? messages.getLabel("invoice_no_comment") : comment);
        commentCell.setFont(PDType1Font.HELVETICA);
        commentCell.setFillColor(Color.WHITE);
        commentCell.setTextColor(Color.DARK_GRAY);

        float newTopOffset = PdfWriterHelper.getHeightOfCell(commentCell, 5, 5, 8);
        if (pdfWriterHelper.top - pdfWriterHelper.initMargin < newTopOffset) {
            pdfWriterHelper.addNewPage();
        }

        PdfTable commentsInfo = new PdfTable(pdfWriterHelper);
        commentsInfo.setLineColor(Color.WHITE);
        commentsInfo.setLineWidth(0);
        PdfRow headerRow = new PdfRow(15f);
        PdfCell cell = new PdfCell(120, messages.getLabel("invoice_comment"));
        cell.setFontSize(10);
        cell.setFont(PDType1Font.HELVETICA_BOLD);
        cell.setFillColor(Color.WHITE);
        cell.setTextColor(Color.DARK_GRAY);
        headerRow.addCell(cell);
        headerRow.addCell(commentCell);
        commentsInfo.drawRow(headerRow);

        commentsInfo.endTable();
    }

    private void addCustomNote(PdfWriterHelper pdfWriterHelper, String note) throws IOException {
        if (GenericTools.isEmpty(note)) {
            return;
        }

        pdfWriterHelper.moveTopPointer(50);

        PdfCell cell = new PdfCell(pdfWriterHelper.getPageContentWidth(), note + "\n ");
        cell.setFont(PDType1Font.HELVETICA);
        cell.setFillColor(PdfWriterHelper.lightGray);
        cell.setFontSize(8);
        cell.setTextColor(Color.DARK_GRAY);

        float newTopOffset = PdfWriterHelper.getHeightOfCell(cell, 5, 5, 8);
        if (pdfWriterHelper.top - pdfWriterHelper.initMargin < newTopOffset) {
            pdfWriterHelper.addNewPage();
        }

        PdfTable noteTable = new PdfTable(pdfWriterHelper);
        noteTable.setLineColor(Color.WHITE);
        noteTable.setLineWidth(0);
        noteTable.setHorizontalCellMargin(10);
        noteTable.setVerticalCellMargin(10);
        PdfRow headerRow = new PdfRow(1);
        headerRow.addCell(cell);
        noteTable.drawRow(headerRow);
        noteTable.endTable();
    }

    private Sale getSampleSale() {
        ServerTools serverTools = new ServerTools();

        Sale sale = new Sale();
        Product product = new Product();
        product.setNumber("0001");
        product.setName(messages.getLabel("product") + " 1");
        product.setDescription(messages.getLabel("product_form_description_help"));

        SaleProductService saleProductService = new SaleProductService();
        saleProductService.setTaxPercent(10D);
        saleProductService.setProduct(product);
        saleProductService.setPrice(20000);
        saleProductService.setQuantity(3);
        sale.getProductsServices().add(saleProductService);

        Payment payment = new Payment();
        payment.setDate(serverTools.addDaysToDate(new Date(), -10));
        payment.setScheduleDate(serverTools.addDaysToDate(new Date(), -20));
        payment.setPaymentMethod(PaymentMethod.bankCheck);
        payment.setAmount(30000D);
        sale.getPayments().add(payment);

        Installment installment = new Installment();
        installment.setDate(new Date());
        installment.setAmount(30000D);
        sale.getInstallments().add(installment);

        InvoiceRecipient invoiceRecipient = new InvoiceRecipient();
        invoiceRecipient.setName(messages.getLabel("client_form_first_name"));
        invoiceRecipient.setEmail(messages.getLabel("client_form_email"));
        Address address = new Address();
        address.setAddressLine1(messages.getLabel("client_form_address"));
        address.setCity(messages.getLabel("client_form_city"));
        address.setCountry(sessionUser.getUser().getEnterprise().getAddress().getCountry());
        address.setZipCode(messages.getLabel("client_form_zip_code") + ",");
        address.setAddressLine2(messages.getLabel("client_form_address1"));

        invoiceRecipient.setAddress(address);
        invoiceRecipient.setPhoneNumber(messages.getLabel("client_form_phone1"));

        sale.setInvoiceRecipient(invoiceRecipient);
        sale.setDate(serverTools.addDaysToDate(new Date(), -25));
        sale.setNumber("000001");
        sale.setTaxPercent(10D);

        return sale;
    }
}
